﻿#region Header

/*
Behavioral Rating of Dancing Human Crowds based on Motion Patterns
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using DexterLib;
using Emgu.CV;
using Emgu.CV.Structure;
using paravili.Services;
using paravili.Steps;
using Sebarf.Services.Interfaces;

#endregion

namespace paravili.CaptureSources {
	/// <summary>
	/// Represents a capture source that gets the images data from the images located
	/// on a dictionary on the physical harddisk
	/// </summary>
	public class WMVVideoBasedCaptureSource : ICapture, IDisposableCaptureSource {
		#region Public Properties

		[ConfigurabelStringValue(Name = "Path of the video")]
		public string VideoPath { get; set; }

		[ConfigurableNumericValue(Name = "Scale Factor", RangeFrom = 0, RangeTo = 3)]
		public int ScaleFactor { get; set; }

		[ConfigurabelStringValue(Name = "Name of the datasource")]
		public string Name { get; set; }

		[ConfigurableNumericValue]
		public int VideoHeight { get; set; }

		[ConfigurableNumericValue]
		public int VideoWidth { get; set; }

		[ConfigurableNumericValue]
		public int VideoFramerate { get; set; }

		[ServiceRequest]
		public IDispatcherLocatorService DispatcherLocatorService { get; set; }

		#endregion

		#region Public Methods

		public WMVVideoBasedCaptureSource() {
			ScaleFactor = 2;
			VideoHeight = 240;
			VideoWidth = 320;
			VideoFramerate = 30;
		}

		#endregion

		#region Private Methods

		//private void Worker() {
		//    m_videoSource = new MediaDetClass {
		//        Filename = Directory.GetCurrentDirectory() + @"\" + VideoPath,
		//        CurrentStream = 0
		//    };
		//    while (m_videoSource.CurrentStream != 0) {
		//        Thread.Sleep(30);
		//    }

		//    while (m_isWorking) {
		//        if (m_storedImages.Count < PreloadFactor) {
		//            m_lock.AcquireWriterLock(Timeout.Infinite);
		//            // capture new frame
		//            int frameRate = VideoFramerate;
		//            var length = (int)m_videoSource.StreamLength * frameRate;
		//            string tmpFileName = @"c:\test.jpg";// Directory.GetCurrentDirectory() + @"\" + Guid.NewGuid() + ".jpg";

		//            // grabe file at position x with a given resolution
		//            m_videoSource.WriteBitmapBits(m_index / (double)frameRate, VideoWidth, VideoHeight, tmpFileName);

		//            m_storedImages.Enqueue(new Image<Bgr, byte>(tmpFileName));
		//            // delete tmp file
		//            File.Delete(tmpFileName);
		//            m_index++;
		//            m_index %= length; ;
		//            m_lock.ReleaseWriterLock();
		//        }
		//        else {
		//            Thread.Sleep(50);
		//        }
		//    }

		//    m_videoSource = null;
		//    m_storedImages.Clear();
		//}

		#endregion

		#region Private Fields

		private const int PreloadFactor = 1;
		private readonly Queue<Image<Bgr, Byte>> m_storedImages = new Queue<Image<Bgr, byte>>();
		private int m_index;

		#endregion

		#region ICapture Members

		public Image<Bgr, byte> QueryFrame() {
			Image<Bgr, byte> toReturn = null;
			if (m_storedImages.Count > 0) {
				return m_storedImages.Dequeue();
			}
			DispatcherLocatorService.GetDispatcher().Invoke(new ThreadStart(delegate {
				int frameRate = VideoFramerate;

				var m_videoSource = new MediaDetClass { Filename = Directory.GetCurrentDirectory() + @"\" + VideoPath, CurrentStream = 0 };
				var length = (int)m_videoSource.StreamLength * frameRate;
				for (int i = 0; i < PreloadFactor; i++) {

					while (m_videoSource.CurrentStream != 0) {
						m_videoSource = new MediaDetClass { Filename = Directory.GetCurrentDirectory() + @"\" + VideoPath, CurrentStream = 0 };
					}


					string tmpFileName = Directory.GetCurrentDirectory() + @"\" + Guid.NewGuid() + ".jpg";

					// grabe file at position x with a given resolution
					m_videoSource.WriteBitmapBits(m_index / (double)frameRate, VideoWidth, VideoHeight, tmpFileName);

					var img = new Image<Bgr, byte>(tmpFileName);
					// delete tmp file
					File.Delete(tmpFileName);
					m_index++;
					m_index %= length;
					for (int y = 0; y < ScaleFactor; y++) {
						img = img.PyrDown();


					}
					m_storedImages.Enqueue(img);
				}

			}));
			return m_storedImages.Dequeue();
		}

		public Image<Bgr, byte> QuerySmallFrame() {
			return QueryFrame().PyrDown();
		}

		#endregion

		#region IDisposableCaptureSource Members

		public Image<Bgr, byte> QueryImage() {
			return QueryFrame();
		}

		public void DoInit() {
		}

		public void DoCleanUp() {
		}

		public bool IsAvailable {
			get { return File.Exists(VideoPath); }
		}

		#endregion
	}
}